package com.hkts.naturalgas.config;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.gson.Gson;
import com.hkts.naturalgas.vo.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Component

public class AuthorizeGatewayFilterFactory extends AbstractGatewayFilterFactory<AuthorizeGatewayFilterFactory.Config>
{
    @Autowired
    private NaturalgasTokenProperties tokenProperties;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private IgnoredUrlsProperties ignoredUrlsProperties;

    public AuthorizeGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("enabled");
    }

    @Override
    public GatewayFilter apply(AuthorizeGatewayFilterFactory.Config config) {
        return (exchange, chain) -> {
            if (!config.isEnabled()) {
                return chain.filter(exchange);
            }
            ServerHttpRequest request = exchange.getRequest();
            //判断是否为不用校验的urls---
            //匿名地址处理
            String serviceName="/"+request.getPath().subPath(1).value();
            String strUri=request.getPath().subPath(2).value();
            List<String> urls = ignoredUrlsProperties.getUrls();
            for(int i=0;i<urls.size();i++){
                String s = urls.get(i);
                if(s.contains("**")){
                    if(s.endsWith("**")){
                        String substring = s.substring(0, s.length() - 2);
                        if(serviceName.contains(substring)){
                            return chain.filter(exchange);
                        }
                    }
                    if(s.startsWith("/**")){
                        String substring = s.substring(3, s.length());
                        if(serviceName.contains(substring)){
                            return chain.filter(exchange);
                        }
                    }
                }else{
                    if(s.equals(serviceName)){
                        return chain.filter(exchange);
                    }
                }

            }


            HttpHeaders headers = request.getHeaders();
            ServerHttpResponse resp = exchange.getResponse();
            String token = headers.getFirst(SecurityConstant.HEADER);

            if(token==null){
                ServerHttpResponse response = exchange.getResponse();
                JSONObject message = new JSONObject();
                message.put("message", "error");
                message.put("code", 401);
                message.put("timestamp", System.currentTimeMillis());
                message.put("result", "请先登录！");
                byte[] bits = message.toJSONString().getBytes(StandardCharsets.UTF_8);
                DataBuffer buffer = response.bufferFactory().wrap(bits);
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                //指定编码，否则在浏览器中会中文乱码
                response.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");
                return response.writeWith(Mono.just(buffer));
            }else{
                String v = redisTemplate.opsForValue().get(SecurityConstant.TOKEN_PRE + token);
                if (StrUtil.isBlank(v)) {
                    ServerHttpResponse response = exchange.getResponse();
                    JSONObject message = new JSONObject();
                    message.put("message", "error");
                    message.put("code", 401);
                    message.put("timestamp", System.currentTimeMillis());
                    message.put("result", "登录超时，请重新登录！");
                    byte[] bits = message.toJSONString().getBytes(StandardCharsets.UTF_8);
                    DataBuffer buffer = response.bufferFactory().wrap(bits);
                    response.setStatusCode(HttpStatus.UNAUTHORIZED);
                    //指定编码，否则在浏览器中会中文乱码
                    response.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");
                    return response.writeWith(Mono.just(buffer));
                }else{
                    String username="";
                    TokenUser user = new Gson().fromJson(v, TokenUser.class);
                    username = user.getUsername();

                    if (!user.getSaveLogin()) {
                        // 若未保存登录状态重新设置失效时间
                        redisTemplate.opsForValue().set(SecurityConstant.USER_TOKEN + username, token, tokenProperties.getTokenExpireTime(), TimeUnit.MINUTES);
                        redisTemplate.opsForValue().set(SecurityConstant.TOKEN_PRE + token, v, tokenProperties.getTokenExpireTime(), TimeUnit.MINUTES);
                    }
                }
            }
            return chain.filter(exchange);
        };
    }
    public static class Config {
        // 控制是否开启认证
        private boolean enabled;

        public Config() {}

        public boolean isEnabled() {
            return enabled;
        }

        public void setEnabled(boolean enabled) {
            this.enabled = enabled;
        }
    }

    /**
     * 认证错误输出
     * @param resp 响应对象
     * @param mess 错误信息
     * @return
     */
    private Mono<Void> authErro(ServerHttpResponse resp,String mess) {
        resp.setStatusCode(HttpStatus.UNAUTHORIZED);
        resp.getHeaders().add("Content-Type","application/json;charset=UTF-8");
        //ReturnData<String> returnData = new ReturnData<>(org.apache.http.HttpStatus.SC_UNAUTHORIZED, mess, mess);
        String returnStr = "没有权限！";
        /*try {
            returnStr = objectMapper.writeValueAsString(returnData);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }*/
        DataBuffer buffer = resp.bufferFactory().wrap(returnStr.getBytes(StandardCharsets.UTF_8));
        return resp.writeWith(Flux.just(buffer));
    }


}
